const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const fse = require("fs-extra");
const path = require("path");
const multipart = require("connect-multiparty");
const multipartMiddleware = multipart();

const app = express();

app.use(cors());
app.use(bodyParser.json());

// 所有上传的文件存放在该目录下
const UPLOADS_DIR = path.resolve("uploads");

// 提供对上传目录的静态文件服务  
app.use('/files', express.static(path.join(__dirname, 'uploads')));

/**
 * 上传
 */
app.post("/upload", multipartMiddleware, (req, res) => {
    const { fileHash, chunkHash } = req.body;

    // 如果临时文件夹(用于保存分片)不存在，则创建
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
    if (!fse.existsSync(chunkDir)) {
        fse.mkdirSync(chunkDir);
    }

    // 如果临时文件夹里不存在该分片，则将用户上传的分片移到临时文件夹里
    const chunkPath = path.resolve(chunkDir, chunkHash);
    if (!fse.existsSync(chunkPath)) {
        fse.moveSync(req.files.chunk.path, chunkPath);
    }

    res.send({
        success: true,
        msg: "上传成功",
    });
});

/**
 * 合并
 */
app.post("/merge", async (req, res) => {
    const { fileHash, fileName } = req.body;

    // 最终合并的文件路径
    const filePath = path.resolve(UPLOADS_DIR, fileHash + path.extname(fileName));
    // 临时文件夹路径
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);

    // 读取临时文件夹，获取该文件夹下“所有文件（分片）名称”的数组对象
    const chunkPaths = fse.readdirSync(chunkDir);

    // 读取临时文件夹获得的文件（分片）名称数组可能乱序，需要重新排序
    chunkPaths.sort((a, b) => a.split("-")[1] - b.split("-")[1]);

    // 遍历文件（分片）数组，将分片追加到文件中
    const pool = chunkPaths.map((chunkName) =>
        new Promise((resolve) => {
            const chunkPath = path.resolve(chunkDir, chunkName);
            // 将分片追加到文件中
            fse.appendFileSync(filePath, fse.readFileSync(chunkPath));
            // 删除分片
            fse.unlinkSync(chunkPath);
            resolve();
        })
    );
    await Promise.all(pool);
    // 等待所有分片追加到文件后，删除临时文件夹
    fse.removeSync(chunkDir);

    res.send({
        code: 200,
        success: true,
        msg: "合并成功,数据上传成功！",
    });
});

/**
 * 校验
 */
app.post("/verify", (req, res) => {
    const { fileHash, fileName } = req.body;

    // 判断服务器上是否存在该hash值的文件
    const filePath = path.resolve(UPLOADS_DIR, fileHash + path.extname(fileName));
    const existFile = fse.existsSync(filePath);

    // 获取已经上传到服务器的文件分片
    const chunkDir = path.resolve(UPLOADS_DIR, fileHash);
    const existChunks = [];
    if (fse.existsSync(chunkDir)) {
        existChunks.push(...fse.readdirSync(chunkDir));
    }

    res.send({
        success: true,
        msg: "校验文件",
        data: {
            existFile,
            existChunks,
        },
    });
});

/**
 * 下载
 */
app.get("/download/:fileHash", (req, res) => {
    const fileHash = req.params.fileHash;
    // 文件完整路径
    const filePath = path.resolve(UPLOADS_DIR, fileHash + path.extname(req.query.fileName));
    console.log(filePath);
    if (!fse.existsSync(filePath)) {
        return res.send({
            success: false,
            msg: "文件不存在"
        });
    }

    // 使用 res.sendFile() 方法发送文件，它会处理好文件头和编码等细节
    res.sendFile(filePath, (err) => {
        if (err) {
            res.send({ success: false, msg: err.message });
        }
    });
});

const server = app.listen(3000, () => {
    console.log(`服务器运行在 http://127.0.0.1:${server.address().port}`);
});
